﻿#include "gst/gst.h"
#include <QCoreApplication>
#include <QDebug>
#include <gst/gst.h>
#include <gst/gstmessage.h>

/*
// 回调函数：处理demuxer的pad-added信号
static void on_pad_added(GstElement *element, GstPad *pad, gpointer data) {
    GstElement *queue = (GstElement *)data;
    GstPad *sinkpad = gst_element_get_static_pad(queue, "sink");

    // 只连接视频或音频pad
    const gchar *pad_name = gst_pad_get_name(pad);
    gboolean is_video = g_str_has_prefix(pad_name, "video");
    gboolean is_audio = g_str_has_prefix(pad_name, "audio");

    if ((is_video || is_audio) && sinkpad) {
        if (gst_pad_link(pad, sinkpad) != GST_PAD_LINK_OK) {
            g_printerr("Failed to link %s pad\n", pad_name);
        }
    }

    if (sinkpad) gst_object_unref(sinkpad);
}
*/

/*
int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    //设置环境变量（调试用）
    qputenv("GST_DEBUG", "2");
    qputenv("GST_PLUGIN_PATH", "D:/gstreamer/1.0/msvc_x86_64/lib/gstreamer-1.0");
    qputenv("PATH", qgetenv("PATH") + ";D:/gstreamer/1.0/msvc_x86_64/bin");

    //初始化GStreamer
    gst_init(&argc, &argv);

    // Create the elements
    GstElement *pipeline = gst_pipeline_new("test-pipeline");
    GstElement *src = gst_element_factory_make("filesrc", "source");
    GstElement *convert1 = gst_element_factory_make("videoconvert", "convert1");
    GstElement *balance = gst_element_factory_make("videobalance", "balance");
    GstElement *convert2 = gst_element_factory_make("videoconvert", "convert2");
    GstElement *scale = gst_element_factory_make("videoscale", "scale");
    GstElement *capsfilter = gst_element_factory_make("capsfilter", "capsfilter");
    GstElement *sink = gst_element_factory_make("autovideosink", "sink");

    // Check all elements were created
    if (!pipeline || !src || !convert1 || !balance || !convert2 || !scale || !capsfilter || !sink) {
        g_printerr("Not all elements could be created.\n");
        return -1;
    }

    // 设置文件路径
    g_object_set(src, "location", "e:\\abc.mp4", NULL);

    // Configure elements
    g_object_set(balance, "saturation", 0.0, NULL);

    // Set caps for the capsfilter
    GstCaps *caps = gst_caps_from_string("video/x-raw,width=800");
    g_object_set(capsfilter, "caps", caps, NULL);
    gst_caps_unref(caps);

    // Add elements to the pipeline
    gst_bin_add_many(GST_BIN(pipeline), src, convert1, balance, convert2, scale, capsfilter, sink, NULL);

    // Link the elements
    if (!gst_element_link_many(src, convert1, balance, convert2, scale, capsfilter, sink, NULL)) {
        g_printerr("Elements could not be linked.\n");
        gst_object_unref(pipeline);
        return -1;
    }

    // Start playing
        gst_object_unref(pipeline);
        return -1;
    }
    GstStateChangeReturn ret = gst_element_set_state(pipeline, GST_STATE_PLAYING);
    if (ret == GST_STATE_CHANGE_FAILURE) {
        g_printerr("Unable to set the pipeline to the playing state.\n");

    // Wait until error or EOS
    GstBus *bus = gst_element_get_bus(pipeline);
    GstMessage *msg = gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE,
                                                 (GstMessageType)(GST_MESSAGE_ERROR | GST_MESSAGE_EOS));

    // Parse message
    if (msg != NULL) {
        GError *err;
        gchar *debug_info;

        switch (GST_MESSAGE_TYPE(msg)) {
        case GST_MESSAGE_ERROR:
            gst_message_parse_error(msg, &err, &debug_info);
            g_printerr("Error received from element %s: %s\n",
                       GST_OBJECT_NAME(msg->src), err->message);
            g_printerr("Debugging information: %s\n", debug_info ? debug_info : "none");
            g_clear_error(&err);
            g_free(debug_info);
            break;
        case GST_MESSAGE_EOS:
            g_print("End-Of-Stream reached.\n");
            break;
        default:
            g_printerr("Unexpected message received.\n");
            break;
        }
        gst_message_unref(msg);
    }

    // Free resources
    gst_object_unref(bus);
    gst_element_set_state(pipeline, GST_STATE_NULL);
    gst_object_unref(pipeline);

    return a.exec();
}
*/

#include "gst/gst.h"
#include <QCoreApplication>
#include <QDebug>
#include <gst/gst.h>
#include <gst/gstmessage.h>

static void on_pad_added(GstElement *src, GstPad *new_pad, gpointer data) {
    GstElement *pipeline = (GstElement *)data;
    GstCaps *caps = gst_pad_get_current_caps(new_pad);

    if (!caps) return;

    GstStructure *structure = gst_caps_get_structure(caps, 0);
    const gchar *media_type = gst_structure_get_name(structure);

    g_print("New pad with media type: %s\n", media_type);

    if (g_str_has_prefix(media_type, "video/")) {
        // 视频路径：queue -> autovideosink
        GstElement *queue = gst_element_factory_make("queue", "video_queue");
        GstElement *sink = gst_element_factory_make("autovideosink", "videosink");

        if (!queue || !sink) {
            g_printerr("Failed to create video elements\n");
            gst_caps_unref(caps);
            return;
        }

        gst_bin_add_many(GST_BIN(pipeline), queue, sink, nullptr);

        // 链接队列到sink
        if (!gst_element_link(queue, sink)) {
            g_printerr("Failed to link video queue to sink\n");
            gst_caps_unref(caps);
            return;
        }

        // 连接新pad到队列
        GstPad *sink_pad = gst_element_get_static_pad(queue, "sink");
        if (!sink_pad) {
            g_printerr("Failed to get sink pad from video queue\n");
            gst_caps_unref(caps);
            return;
        }

        GstPadLinkReturn ret = gst_pad_link(new_pad, sink_pad);
        if (ret != GST_PAD_LINK_OK) {
            g_printerr("Failed to link video pads: %s\n", gst_pad_link_get_name(ret));
        } else {
            g_print("Successfully linked video pads!\n");
        }

        gst_object_unref(sink_pad);

        // 同步元素状态
        gst_element_sync_state_with_parent(queue);
        gst_element_sync_state_with_parent(sink);
    }
    else if (g_str_has_prefix(media_type, "audio/")) {
        // 音频路径：audioconvert -> audioresample -> queue -> autoaudiosink
        GstElement *audioconvert = gst_element_factory_make("audioconvert", "audio_convert");
        GstElement *audioresample = gst_element_factory_make("audioresample", "audio_resample");
        GstElement *queue = gst_element_factory_make("queue", "audio_queue");
        GstElement *sink = gst_element_factory_make("autoaudiosink", "audiosink");

        if (!audioconvert || !audioresample || !queue || !sink) {
            g_printerr("Failed to create audio elements\n");
            gst_caps_unref(caps);
            return;
        }

        // 关键设置：禁用音频同步，增加缓冲区
        g_object_set(sink, "sync", FALSE, NULL);
        g_object_set(queue, "max-size-buffers", 200, NULL);
        g_object_set(queue, "max-size-time", 1000000000, NULL); // 1秒缓冲

        gst_bin_add_many(GST_BIN(pipeline), audioconvert, audioresample, queue, sink, nullptr);

        // 链接音频处理链：audioconvert -> audioresample -> queue -> sink
        if (!gst_element_link_many(audioconvert, audioresample, queue, sink, nullptr)) {
            g_printerr("Failed to link audio elements\n");
            gst_caps_unref(caps);
            return;
        }

        // 连接新pad到audioconvert
        GstPad *sink_pad = gst_element_get_static_pad(audioconvert, "sink");
        if (!sink_pad) {
            g_printerr("Failed to get sink pad from audioconvert\n");
            gst_caps_unref(caps);
            return;
        }

        GstPadLinkReturn ret = gst_pad_link(new_pad, sink_pad);
        if (ret != GST_PAD_LINK_OK) {
            g_printerr("Failed to link audio pads: %s\n", gst_pad_link_get_name(ret));
        } else {
            g_print("Successfully linked audio pads with format conversion!\n");
        }

        gst_object_unref(sink_pad);

        // 同步元素状态
        gst_element_sync_state_with_parent(audioconvert);
        gst_element_sync_state_with_parent(audioresample);
        gst_element_sync_state_with_parent(queue);
        gst_element_sync_state_with_parent(sink);
    }

    gst_caps_unref(caps);
}

int main(int argc, char *argv[]) {
    // 设置调试信息
    g_setenv("GST_DEBUG", "4", TRUE);

    // 设置环境变量避免D3D调试问题
    g_setenv("GST_D3D11_DEBUG", "none", TRUE);
    g_setenv("GST_D3D12_DEBUG", "none", TRUE);

    /* 初始化 GStreamer */
    gst_init(&argc, &argv);

    // 检查参数
    if (argc != 2) {
        g_printerr("Usage: %s <video file>\n", argv[0]);
        return -1;
    }

    // 创建管道和元素
    GstElement *pipeline = gst_pipeline_new("pipeline");
    GstElement *filesrc = gst_element_factory_make("filesrc", "filesrc");
    GstElement *decodebin = gst_element_factory_make("decodebin", "decoder");

    if (!pipeline || !filesrc || !decodebin) {
        g_printerr("Failed to create pipeline elements\n");
        return -1;
    }

    // 设置文件路径
    g_object_set(filesrc, "location", argv[1], nullptr);

    // 添加元素到管道
    gst_bin_add_many(GST_BIN(pipeline), filesrc, decodebin, nullptr);

    // 链接filesrc到decodebin
    if (!gst_element_link(filesrc, decodebin)) {
        g_printerr("Failed to link filesrc to decodebin\n");
        gst_object_unref(pipeline);
        return -1;
    }

    // 连接decodebin的信号
    g_signal_connect(decodebin, "pad-added", G_CALLBACK(on_pad_added), pipeline);

    // 启动管道
    GstStateChangeReturn ret = gst_element_set_state(pipeline, GST_STATE_PLAYING);
    if (ret == GST_STATE_CHANGE_FAILURE) {
        g_printerr("Failed to start pipeline\n");
        gst_object_unref(pipeline);
        return -1;
    }

    // 运行主循环
    GstBus *bus = gst_element_get_bus(pipeline);
    GstMessage *msg = gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE,
                                                 (GstMessageType)(GST_MESSAGE_ERROR | GST_MESSAGE_EOS | GST_MESSAGE_WARNING));

    // 处理消息
    if (msg != NULL) {
        GError *err = NULL;
        gchar *debug_info = NULL;

        switch (GST_MESSAGE_TYPE(msg)) {
        case GST_MESSAGE_ERROR:
            gst_message_parse_error(msg, &err, &debug_info);
            g_printerr("Error: %s\n", err->message);
            if (debug_info) {
                g_printerr("Debug info: %s\n", debug_info);
            }
            g_clear_error(&err);
            g_free(debug_info);
            break;
        case GST_MESSAGE_WARNING:
            gst_message_parse_warning(msg, &err, &debug_info);
            g_printerr("Warning: %s\n", err->message);
            if (debug_info) {
                g_printerr("Debug info: %s\n", debug_info);
            }
            g_clear_error(&err);
            g_free(debug_info);
            break;
        case GST_MESSAGE_EOS:
            g_print("End of stream reached.\n");
            break;
        default:
            g_printerr("Unexpected message type: %d\n", GST_MESSAGE_TYPE(msg));
        }
        gst_message_unref(msg);
    }

    // 清理资源
    gst_object_unref(bus);
    gst_element_set_state(pipeline, GST_STATE_NULL);
    gst_object_unref(pipeline);

    return 0;
}
